﻿using System;
using System.IO;
using System.Linq;
using RayDen.Library.Core.Collections;
using RayDen.Library.Core.Primitives;


namespace RayDen.Library.Data.Imaging
{
    public enum RayDenImageFormats
    {
        Default = 0, // 3 band spectrum without modifications
        XYZ = 1 << 1,
        sRGB = 1 << 2,
        bRGB = 1 << 3,
        Intensity = 1 << 4,
        EightBandSpectrum = 1 << 5,
    }

    [Flags]
    public enum RayDenImageFlags
    {
        None = 1 << 0,
        GammaCorrected = 1 << 1,
        ToneMapped = 1 << 2,
    }

    public class RayDenImageHeader
    {
        public uint Sign;
        public int Width;
        public int Height;
        public int ElementSize;
        public RayDenImageFlags ImageFlags;
        public RayDenImageFormats Format;
        public RayDenImageHeader()
        {
            Sign = 0x7F7Fu;
        }
    }

    public class RayDenImageData<TData, TWeight>
        where TData : struct
        where TWeight : struct
    {
        public TData[] Data;
        public TWeight[] Weight;


        public RayDenImageData(TData[] data, TWeight[] weight)
        {
            this.Data = data;
            this.Weight = weight;
        }


    }

    public class RayDenBasicImage
    {
        public RayDenImageHeader ImageInfo;
        public RayDenImageData<RgbSpectrum, float> ImageData;
        public bool ApplyWeight { get; set; }


        public RayDenBasicImage(int width, int height, RgbSpectrum[] data, float[] weight)
        {
            this.ImageData = new RayDenImageData<RgbSpectrum, float>(data, weight);
            this.ImageInfo = new RayDenImageHeader() { Width = width, Height = height, ElementSize = 96, Format = RayDenImageFormats.Default };
        }

        public RayDenBasicImage(FilmFrame filmFrame)
        {
            this.ImageData = new RayDenImageData<RgbSpectrum, float>(filmFrame.Data, filmFrame.Weight);
            this.ImageInfo = new RayDenImageHeader() { Width = filmFrame.Width, Height = filmFrame.Height, ElementSize = 96, Format = RayDenImageFormats.Default };
        }

        public void Save(string fileName, RayDenImageFlags flags,
                         RayDenImageFormats format = RayDenImageFormats.Default)
        {
            this.ImageInfo.Format = format;
            this.ImageInfo.ImageFlags = flags;

            using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            using (var bw = new BinaryWriter(fs))
            {
                bw.Write(this.ImageInfo.Sign);
                bw.Write(this.ImageInfo.Width);
                bw.Write(this.ImageInfo.Height);
                bw.Write(this.ImageInfo.ElementSize);
                bw.Write((int)this.ImageInfo.Format);
                bw.Write((int)this.ImageInfo.ImageFlags);

                var floatArrayData = this.ImageData.Data.ToFloatList().ToArray();
                var byteArray = new byte[floatArrayData.Length * 4];
                Buffer.BlockCopy(floatArrayData, 0, byteArray, 0, byteArray.Length);
                bw.Write(byteArray);
            }
        }


        public void Load(string fileName)
        {
            using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            using (var bw = new BinaryReader(fs))
            {
                this.ImageInfo.Sign = bw.ReadUInt32();
                this.ImageInfo.Width = bw.ReadInt32();
                this.ImageInfo.Height = bw.ReadInt32();
                this.ImageInfo.ElementSize = bw.ReadInt32();
                this.ImageInfo.Format = (RayDenImageFormats) bw.ReadInt32();
                this.ImageInfo.ImageFlags = (RayDenImageFlags) bw.ReadInt32();

                var floatArrayData = new float[this.ImageInfo.Width*this.ImageInfo.Height*3];
                var byteArray = new byte[floatArrayData.Length * 4];
                bw.Read(byteArray, 0, floatArrayData.Length*4);
                Buffer.BlockCopy(byteArray,0, floatArrayData,  0, byteArray.Length);
            }
        }


        protected virtual void ScaleWeight()
        {

        }
    }
}
